package com.fuce.one.deploy.util;

import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.setting.Setting;
import com.fuce.one.deploy.common.base.AjaxResult;
import com.fuce.one.deploy.common.base.TomcatVo;
import com.fuce.one.deploy.model.WebApp;
import cn.hutool.core.codec.Base64;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

/**
 * Tomcat 方法类
 * @ClassName: TomcatUtil
 * @author fuce
 * @date 2020-03-01 02:17
 */
public class TomcatUtil {

    private static Setting setting = new Setting("config/config.setting");

    public static Setting getSetting() {
        return setting;
    }

    public static void setSetting(Setting setting) {
        TomcatUtil.setting = setting;
    }


    public static String message(String operateURL) {
        StringBuffer dataResult = new StringBuffer();
        URL url = null;
        try {
            url = new URL(operateURL);

            URLConnection conn = (URLConnection) url.openConnection();
            //这里我是把admin，123456 这个用户信息放到了一个json文件中以json形式存放，然后取出来，如果不是以这种方式存放，则可以直接设置username = admin ，password =123456

            String username ="admin";
            String password ="1";

            String configuration = username+":"+password; // manager角色的用户

            String encodedPassword =Base64.encode(configuration.getBytes());
            conn.setRequestProperty("Authorization", "Basic " + encodedPassword);
            // URL授权访问 -- End

            InputStream is = conn.getInputStream();
            BufferedReader bufreader = new BufferedReader(new InputStreamReader(is));
            String line = null;
            while ((line = bufreader.readLine()) != null) {
                dataResult.append(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return dataResult.toString();
    }

    /**
     * 获取tomcat正在运行的webApp的参数
     * @return
     */
    public static ArrayList<WebApp> getTomcatWebAppData(){
        ArrayList<WebApp> webAppArrayList = new ArrayList<WebApp>();
        List<String> groups = setting.getGroups();
        for (int j = 0; j < groups.size(); j++) {
            try {
                String groupName = groups.get(j);
                String ip = setting.getByGroup("ip", groupName);
                String port = setting.getByGroup("port", groupName);

                String data = TomcatUtil.message("http://" + ip + ":" + port + "/manager/text/list");
                String[] oldDataStrs = data.split("/");

                if (oldDataStrs[0].startsWith("OK")) {
                    for (int i = 1; i < oldDataStrs.length; i++) {
                        String name = oldDataStrs[i].split(":")[3];
                        String projectUrl = oldDataStrs[i].split(":")[0];
                        WebApp webApp = new WebApp();
                        webApp.setUrl("/" + projectUrl);
                        webApp.setName(name);
                        webApp.setTomcatName(groupName);
                        webApp.setIp(ip);
                        webApp.setPort(port);
                        if (oldDataStrs[i].split(":")[1].equals("running")) {
                            if (oldDataStrs[i].split(":")[2].equals("0")) {
                                webApp.setStatus("运行");
                            } else {
                                webApp.setStatus("异常");
                            }
                        } else if (oldDataStrs[i].split(":")[1].equals("stopped")) {
                            if (oldDataStrs[i].split(":")[2].equals("0")) {
                                webApp.setStatus("停止");
                            } else {
                                webApp.setStatus("异常");
                            }
                        } else {
                            webApp.setStatus("异常");
                        }
                        webAppArrayList.add(webApp);
                    }
                }
            } catch (Exception e){
                e.printStackTrace();
                continue;
            }
        }


        return webAppArrayList;
    }

    /**
     * 部署现有的应用程序
     * @param webAppName
     * @return
     */
    public static boolean deployWebApp(String webAppName,String tomcatName){
        String ip = setting.getByGroup("ip", tomcatName);
        String port = setting.getByGroup("port", tomcatName);
        String data = TomcatUtil.message("http://"+ip+":"+port+"/manager/text/deploy?war="+webAppName);
        System.out.println(data);

        if(data.startsWith("OK")){
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * 重新加载现有的应用程序
     * @param webAppName
     * @return
     */
    public static boolean reloadWebApp(String webAppName,String tomcatName){
        String ip = setting.getByGroup("ip", tomcatName);
        String port = setting.getByGroup("port", tomcatName);
        String data = TomcatUtil.message("http://"+ip+":"+port+"/manager/text/reload?path=/"+webAppName);
        System.out.println(data);
        if(data.startsWith("OK")){
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * 停止一个项目
     * @param webAppName
     * @return
     */
    public static boolean stopWebApp(String webAppName,String tomcatName){
        String ip = setting.getByGroup("ip", tomcatName);
        String port = setting.getByGroup("port", tomcatName);
        String data = TomcatUtil.message("http://"+ip+":"+port+"/manager/text/stop?path=/"+webAppName);
        System.out.println(data);
        if(data.startsWith("OK")){
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * 取消部署现有应用程序
     * 警告 -此命令将删除appBase此虚拟主机的目录（通常为“ webapps”）中存在的所有Web应用程序工件。
     * @param webAppName
     * @return
     */
    public static boolean undeployWebApp(String webAppName,String tomcatName){
        String ip = setting.getByGroup("ip", tomcatName);
        String port = setting.getByGroup("port", tomcatName);
        String data = TomcatUtil.message("http://"+ip+":"+port+"/manager/text/undeploy?path=/"+webAppName);
        System.out.println(data);

        if(data.startsWith("OK")){
            return true;
        }
        else {
            return false;
        }
    }



    /**
     * 开始一个项目
     * @param webAppName
     * @return
     */
    public static boolean startWebApp(String webAppName,String tomcatName){
        String ip = setting.getByGroup("ip", tomcatName);
        String port = setting.getByGroup("port", tomcatName);
        String data = TomcatUtil.message("http://"+ip+":"+port+"/manager/text/start?path=/"+webAppName);
        System.out.println(data);

        if(data.startsWith("OK")){
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * 查询tomcat指定文件夹下面所有的文件
     * @param projectName
     * @param tomcatName
     * @return
     * @author fuce
     * @Date 2020年3月7日 下午5:30:43
     */
    public static AjaxResult getDirAndFilePath(String projectName, String tomcatName) {
        try {
            String tomcatPath = setting.getByGroup("address", tomcatName);
            if (StringUtils.isEmpty(tomcatPath)) {
                return AjaxResult.error("未找到tomcat路径");
            }
            String projectPath = tomcatPath + "\\" + projectName;
            //获取最高级文件夹路径
            File file = new File(projectPath);
            Map<String, Object> filePath = getFilePath(file);
            List list = new ArrayList();
            list.add(filePath);
            return AjaxResult.successData(200,list);

        } catch (Exception e){
            e.printStackTrace();
        }
        return AjaxResult.error("查询出错");
    }



    /**
     * 递归查询所有的文件
     * @param file
     * @return
     * @author fuce
     * @Date 2020年3月7日 下午5:34:22
     */
    private static Map<String, Object> getFilePath(File file) {
        Map<String, Object> map = new HashMap<String,Object>();
        map.put("name",file.getName());

        List<Object> childDirList = new ArrayList<Object>();

        File[] files = file.listFiles();

        for(int i = 0;i<files.length;i++){

            File childFile = files[i];

            //如果他是文件夹
            if(childFile.isDirectory()){
                childDirList.add(getFilePath(childFile));
            } else {
                Map<String, String> fileMap = new HashMap<String, String>();
                fileMap.put("name",childFile.getName());
                childDirList.add(fileMap);
            }
        }
        map.put("children",childDirList);
        return map;
    }

    /**
     * 上传单个文件或者zip解压方法
     * @param file
     * @param projectUrl
     * @param tomcatName
     * @return
     * @throws IOException
     * @author fuce
     * @Date 2020年3月7日 下午5:35:20
     */
    public static boolean updateFiles(MultipartFile file, String projectUrl, String tomcatName) throws IOException {
        String tomcatAdd = setting.getByGroup("address", tomcatName);
        try {
            //判断tomcat地址是否存在
            if(StringUtils.isEmpty(tomcatAdd)){
                return false;
            }
            if (file != null) {
                String fileRealName = file.getOriginalFilename();//获得原始文件名;
                boolean b = fileRealName.endsWith(".zip");
                //临时存放文件地址
                String insertPath = tomcatAdd.replace("\\webapps","")+"\\temp";

                //更新文件的实际地址

                // 证明是zip文件
                if(b){
                    String updateFile = tomcatAdd+projectUrl+"\\";

                    //转换成file文件-----
                    InputStream ins = null;
                    ins = file.getInputStream();
                    File toFile = new File(insertPath+"\\"+file.getOriginalFilename());
                    if(toFile.exists()){
                        toFile.delete();
                    }
                    OutputStream os = new FileOutputStream(toFile);
                    int bytesRead = 0;
                    byte[] buffer = new byte[10240];
                    while ((bytesRead = ins.read(buffer, 0, 10240)) != -1) {
                        os.write(buffer, 0, bytesRead);
                    }
                    os.close();
                    ins.close();



                    //解压上传 zip
                    String zipUrl = insertPath + "\\" + fileRealName;
                   // boolean b1 = ZipUtil.unZipFiles(zipUrl, updateFile);
                    ZipUtil.unzip(zipUrl,updateFile, Charset.forName("GBK"));
                    //删除上传的zip
                    File deleteFile = new File(zipUrl);
                    deleteFile.delete();
                    return true;
                } else{
                    String updateFile = tomcatAdd+projectUrl;

                    InputStream ins = file.getInputStream();
                    int i = updateFile.lastIndexOf("\\");
                    updateFile = updateFile.substring(0, i);
                    OutputStream os = new FileOutputStream(updateFile+"\\"+fileRealName);
                    // 证明是单独文件
                    int bytesRead = 0;
                    byte[] buffer = new byte[1024000];
                    while ((bytesRead = ins.read(buffer, 0, 1024000)) != -1) {
                        os.write(buffer, 0, bytesRead);
                    }
                    os.close();
                    ins.close();
                    return true;
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 在指定的tomcat中部署manager
     * @param tomcatName
     * @return
     */
    public static boolean putManager(String tomcatName) {
        try {
            String address = setting.getByGroup("address", tomcatName);
            String path = ClassUtils.getDefaultClassLoader().getResource("").getPath() + "/manager/manager.war";
            File file = new File(path);

            File toFile = new File(address + "\\manager.war");
            FileInputStream fis = new FileInputStream(file);

            FileOutputStream fos = new FileOutputStream(toFile);
            int bytesRead = 0;
            byte[] buffer = new byte[1024000];
            while ((bytesRead = fis.read(buffer, 0, 1024000)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
            fos.close();
            fis.close();
            return true;
        } catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }


    /**
     * 将页面传入的新建tomcat值存入setting配置文件中
     * @param tomcatVo
     * @return
     */
    public static boolean saveTomcat(TomcatVo tomcatVo){
        try {
            String replace = tomcatVo.getAddress().replace("\\webapps", "");
            String filePath = replace +"\\conf\\tomcat-users.xml";
            File file = new File(filePath);
            SAXReader reader = new SAXReader();
            Document document = reader.read(file);
            boolean b = addElement(document, file, "admin", "1");
            if(b){
                return saveTomcatToSetting(tomcatVo);

            }
        } catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }

    private static boolean saveTomcatToSetting(TomcatVo tomcatVo) {
        String path = ClassUtils.getDefaultClassLoader().getResource("").getPath();
        path = path.substring(1, path.length());
        List<String> groups = setting.getGroups();
        for (int i = 0; i < groups.size(); i++) {
            String s = groups.get(i);
            if(s.equals("11")){
                return false;
            }
        }

        String groupName = tomcatVo.getTomcatName();
        setting.put(groupName,"ip",tomcatVo.getIp());
        setting.put(groupName,"port",tomcatVo.getPort());
        setting.put(groupName,"address",tomcatVo.getAddress());
        setting.put(groupName,"username",tomcatVo.getUsername());
        setting.put(groupName,"password",tomcatVo.getPassword());
        setting.store(path+"/config/config.setting");
        return true;
    }

    /**
     * 保存信息到setting
     * @param document
     * @param file
     * @param username
     * @param password
     * @return
     * @throws IOException
     */
    private static boolean addElement(Document document, File file,String username,String password) throws IOException {
        try {
            Element root = document.getRootElement();
            System.out.println(root.getName());
           
            Element role1 = root.addElement("role");
            role1.addAttribute("rolename", "manager-status");
            Element role2 = root.addElement("role");
            role2.addAttribute("rolename", "manager");
            Element role3 = root.addElement("role");
            role3.addAttribute("rolename", "manager-jmx");
            Element role4 = root.addElement("role");
            role4.addAttribute("rolename", "manager-gui");
            Element role5 = root.addElement("role");
            role5.addAttribute("rolename", "manager-script");
            Element role6 = root.addElement("role");
            role6.addAttribute("rolename", "admin");
            Element itemElement = root.addElement("user");
            itemElement.addAttribute("username", username);
            itemElement.addAttribute("password", password);
            itemElement.addAttribute("roles", "manager,manager-gui,admin,manager-status,manager-jmx,manager-script");
            
            OutputFormat format = OutputFormat.createPrettyPrint();
            XMLWriter xmlWriter = new XMLWriter(new FileOutputStream(file), format);
            xmlWriter.write(document);
            xmlWriter.close();
            return true;
        } catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除setting中指定tomcat的信息（待开发）
     * @param tomcatName
     * @return
     */
    public static boolean cancelTomcat(String tomcatName) {
        try {
            setting.clear(tomcatName);
            return true;
        } catch (Exception e){
            e.printStackTrace();
        }
        return false;
    }
}
